package com.goodwill.hdr.mrr;

import com.goodwill.hdr.dao.ConsoleQueryDao;
import com.goodwill.hdr.vo.PropertyFilter;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service
public class ImportSolrService implements ApplicationRunner {


    private final ConsoleQueryDao queryDao;

    private Logger logger = LoggerFactory.getLogger(ImportSolrService.class);

    private final CloudSolrServer solrServer;


    private final Connection connection;

    @Value("${pid}")
    private String pid;
    @Value("${vType}")
    private String vType;
    @Value("${oid}")
    private String oid;
    @Value("${vid}")
    private String vid;

    public ImportSolrService(ConsoleQueryDao queryDao, CloudSolrServer solrServer, Connection connection) {
        this.queryDao = queryDao;
        this.solrServer = solrServer;
        this.connection = connection;
    }

    public void importSolr() {



        List<PropertyFilter> propertyFilterList = new ArrayList<>();
        List<SolrInputDocument> solrDocs = new ArrayList<SolrInputDocument>();
        ResultScanner scanner = null;
        Table table = null;
        Scan scan = new Scan();
        String tableName = "HDR_EMR_CONTENT";
        logger.info("[{准备查询hbase表 " + tableName + "}]");
        String[] columns = {"MR_CONTENT_TEXT", "MR_CONTENT_HTML", "IN_PATIENT_ID", "OUT_PATIENT_ID", "OID",
                "VISIT_ID", "VISIT_TYPE_CODE", "VISIT_TYPE_NAME", "TOPIC", "CREATOR_NAME", "CREATOR_ID",
                "MR_CLASS_NAME", "MR_CLASS_CODE", "PATIENT_CUR_DEPT_CODE", "CREATE_DATE_TIME", "CAPTION_DATE_TIME"};
        if (!pid.equals("default") && !vid.equals("default") && !vType.equals("default") && !oid.equals("default")) {
            logger.info("当前处理的患者坐标为{}，{}，{}，{}",pid,vid,vType,oid);
            propertyFilterList.add(new PropertyFilter("VISIT_ID","String","=",vid));
            propertyFilterList.add(new PropertyFilter("VISIT_TYPE_CODE","String","=",vid));
            List<Map<String, String>> mapList = queryDao.queryHBaseTableData(tableName, pid, oid, propertyFilterList, columns);
            String diagPid = "";
            String diagVisitId = "";
            for (Map<String,String> map:mapList){
                SolrInputDocument doc = new SolrInputDocument();
                doc.addField("id", map.get("rowKey"));
                if (filterDefectData(map.get("rowKey"), map)) {
                    continue;
                }
                addSolrDocFromMap(doc, map);

                doc.addField("PATIENT_VISIT_ID", pid + "|" + vid);
                if (!(diagPid.equals(pid) && diagVisitId.equals(vid))) {
                    String diag = getDiag(pid, vid, vType, oid);
                    doc.addField("MAIN_DIAG", diag);

                    Map<String, String> visitInfo = getVisitInfo(pid, vid, vType, oid);
                    for (Map.Entry<String, String> entry : visitInfo.entrySet()) {
                        String field = entry.getKey();
                        String value = entry.getValue();
                        doc.addField(field, value.replace(" ", "T") + "Z");
                    }
                }
                diagPid = pid;
                diagVisitId = vid;

                String age = doc.get("AGE_VALUE") == null ? "" : doc
                        .get("AGE_VALUE").getValue().toString();
                String ageUnit = doc.get("AGE_UNIT") == null ? "" : doc
                        .get("AGE_UNIT").getValue().toString();
                if (StringUtils.isNotBlank(age)&&StringUtils.isNotBlank(ageUnit)) {

                        // 将年龄全部转换为天数，这样方便前台各种自定义条件查询
                        if ("岁".equals(ageUnit)) {
                            doc.addField("AGE_NUM", String.valueOf(Integer
                                    .parseInt(age) * 365));

                        } else if ("月".equals(ageUnit)) {

                            doc.addField("AGE_NUM", String.valueOf(Integer
                                    .parseInt(age) * 30));
                        } else if ("天".equals(age)) {
                            doc.addField("AGE_NUM", age);
                        }

                } else {
                    logger.info("未发现年龄数据,id:" + doc.get("id").toString());
                }
                solrDocs.add(doc);

            }
            try {
                if (solrDocs.size() > 0) {
                    solrServer.add(solrDocs);
                    solrServer.commit();
                }
            }catch (SolrServerException | IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (scanner != null) {
                    scanner.close();
                }
                if (table != null) {
                    try {
                        table.close();
                    } catch (IOException e) {
                        throw new RuntimeException("hbase table 关闭失败", e);
                    }
                }

            }
        } else {
            try {

                queryDao.addFilterList(propertyFilterList, scan);

                for (String column : columns) {
                    scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes(column));
                }


                table = connection.getTable(TableName.valueOf(tableName));
                scanner = table.getScanner(scan);


                String diagPid = "";
                String diagVisitId = "";

                for (Result result : scanner) {
                    SolrInputDocument doc = new SolrInputDocument();
                    // 将rowkey添加为id
                    String rowkey = new String(result.getRow());
                    doc.addField("id", rowkey);
                    NavigableMap<byte[], NavigableMap<byte[], byte[]>> noVersionMap = result.getNoVersionMap();
                    NavigableMap<byte[], byte[]> map = noVersionMap.get(Bytes.toBytes("cf"));
                    Map<String, String> stringMap = byteMapToStringMap(map);
                    //病历为空则直接跳过
                    if (filterDefectData(rowkey, stringMap)) {
                        continue;
                    }

                    addSolrDocFromMap(doc, stringMap);
                    // 查询诊断数据
                    // 如果当前患者id和住院次和上条数据相同，则不重新读取数据
                    String pid = doc.get("PATIENT_ID").getValue().toString();
                    String vid = doc.get("VISIT_ID").getValue().toString();
                    String oid = doc.get("OID").getValue().toString();
                    doc.addField("PATIENT_VISIT_ID", pid + "|" + vid);
                    String vTypeCode = doc.get("VISIT_TYPE_CODE").getValue().toString();
                    if (!(diagPid.equals(pid) && diagVisitId.equals(vid))) {
                        String diag = getDiag(pid, vid, vTypeCode, oid);
                        doc.addField("MAIN_DIAG", diag);

                        Map<String, String> visitInfo = getVisitInfo(pid, vid, vTypeCode, oid);
                        for (Map.Entry<String, String> entry : visitInfo.entrySet()) {
                            String field = entry.getKey();
                            String value = entry.getValue();
                            doc.addField(field, value.replace(" ", "T") + "Z");
                        }
                    }
                    diagPid = pid;
                    diagVisitId = vid;

                    String age = doc.get("AGE_VALUE") == null ? "" : doc
                            .get("AGE_VALUE").getValue().toString();
                    String ageUnit = doc.get("AGE_UNIT") == null ? "" : doc
                            .get("AGE_UNIT").getValue().toString();
                    if (StringUtils.isNotBlank(age)&&StringUtils.isNotBlank(ageUnit)) {

                        // 将年龄全部转换为天数，这样方便前台各种自定义条件查询
                        if ("岁".equals(ageUnit)) {
                            doc.addField("AGE_NUM", String.valueOf(Integer
                                    .parseInt(age) * 365));

                        } else if ("月".equals(ageUnit)) {

                            doc.addField("AGE_NUM", String.valueOf(Integer
                                    .parseInt(age) * 30));
                        } else if ("天".equals(age)) {
                            doc.addField("AGE_NUM", age);
                        }

                    } else {
                        logger.info("未发现年龄数据,id:" + doc.get("id").toString());
                    }
                    solrDocs.add(doc);
                    if (solrDocs.size() % 500 == 0) {
                        solrServer.add(solrDocs);
                        solrServer.commit();
                        solrDocs = new ArrayList<>();
                    }
                }
                if (solrDocs.size() > 0) {
                    solrServer.add(solrDocs);
                    solrServer.commit();
                }
            } catch (SolrServerException | IOException e) {
                throw new RuntimeException(e);
            } finally {
                if (scanner != null) {
                    scanner.close();
                }
                if (table != null) {
                    try {
                        table.close();
                    } catch (IOException e) {
                        throw new RuntimeException("hbase table 关闭失败", e);
                    }
                }

            }
        }


    }

    private static void addSolrDocFromMap(SolrInputDocument doc, Map<String, String> stringMap) {
        for (String field : stringMap.keySet()) {
            String resultValue = stringMap.get(field);
            if (field.equals("CREATE_DATE_TIME") || field.equals("CAPTION_DATE_TIME")) {
                resultValue = resultValue.replace(" ", "T") + "Z";
            }
            if ("IN_PATIENT_ID".equals(field) || "OUT_PATIENT_ID".equals(field)) {
                continue;
            }
            doc.addField(field, resultValue);

        }
    }

    private boolean filterDefectData(String rowkey, Map<String, String> stringMap) {
        if (StringUtils.isBlank(stringMap.get("MR_CONTENT_TEXT")) &&
                StringUtils.isBlank(stringMap.get("MR_CONTENT_HTML"))) {
            logger.error("{}的MR_CONTENT_TEXT和MR_CONTENT_HTML均为空",rowkey);
            return true;
        }
//            PID为空则直接跳过
        if (StringUtils.isBlank(stringMap.get("IN_PATIENT_ID")) &&
                StringUtils.isBlank(stringMap.get("OUT_PATIENT_ID"))) {
            logger.error("{}的IN_PATIENT_ID和OUT_PATIENT_ID均为空", rowkey);
            return true;
        }
        if (StringUtils.isBlank(stringMap.get("OID"))) {
            logger.error("{}的OID为空", rowkey);
            return true;
        }
        stringMap.put("PATIENT_ID", StringUtils.isNotBlank(stringMap.get("IN_PATIENT_ID")) ? stringMap.get("IN_PATIENT_ID") : stringMap.get("OUT_PATIENT_ID"));
//            visitId为空直接跳过
        if (StringUtils.isBlank(stringMap.get("VISIT_ID"))) {
            return true;
        }
        return false;
    }

    private Map<String, String> getVisitInfo(String pid, String vid, String vTypeCode, String oid) {
        String tableName = "";
        String[] columns = new String[3];
        columns[2] = "PERSON_NAME";
        List<PropertyFilter> filters = new ArrayList<>();
        if ("02".equals(vTypeCode)) {
            tableName = "HDR_INP_SUMMARY";
            columns[0] = "ADMISSION_TIME";
            columns[1] = "DISCHARGE_TIME";

        } else {
            tableName = "HDR_OUT_VISIT";
            columns[0] = "VISIT_TIME";
            columns[1] = "REGISTING_TIME";
        }
        filters.add(new PropertyFilter("VISIT_ID", "String", "=", vid));

        List<Map<String, String>> list = queryDao.queryHBaseTableData(tableName, pid, oid, filters, columns);
        if (list.isEmpty()) {
            logger.error("{},{},{}未查出数据", tableName, pid, vid);
            return new HashMap<>();
        }
        Map<String, String> map = list.get(0);
        map.remove("VISIT_ID");
        return map;
    }


    private String getDiag(String pid, String visitId, String visitTypeCode, String oid) {
        String tableName = "";
        if ("02".equals(visitTypeCode)) {
            List<PropertyFilter> filters = new ArrayList<>();
            filters.add(new PropertyFilter("VISIT_ID", "String", "=", visitId));
            filters.add(new PropertyFilter("TRANS_NO", "String", "=", "0"));
            List<Map<String, String>> list = queryDao.queryHBaseTableData("HDR_PAT_ADT", pid, oid, filters, "DISCHARGE_TIME");
            if (list.isEmpty()) {
                logger.error("{}，{}未查询到诊断信息", pid, visitId);
                return "";

            }
            String dischargeTime = list.get(0).get("DISCHARGE_TIME");

            if (StringUtils.isNotBlank(dischargeTime)) {
//                已出院患者查询病案首页诊断表
                tableName = "HDR_INP_SUMMARY_DIAG";
            } else {
                tableName = "HDR_EMR_CONTENT_DIAG";
            }

        } else {
            tableName = "HDR_OUT_VISIT_DIAG";
        }

        List<PropertyFilter> filters1 = new ArrayList<>();
        filters1.add(new PropertyFilter("VISIT_ID", "String", "=", visitId));
        filters1.add(new PropertyFilter("DIAGNOSIS_NUM", "String", "=", "1"));
        List<Map<String, String>> list1 = queryDao.queryHBaseTableData(tableName, pid, oid, filters1, "DIAGNOSIS_NAME");
        if (list1.isEmpty()) {
            logger.error("{},{},{}未查出数据", tableName, pid, visitId);
            return "";
        }
        return list1.get(0).get("DIAGNOSIS_NAME");

    }


    private Map<String, String> byteMapToStringMap(Map<byte[], byte[]> source) {
        Map<String, String> result = new HashMap<>();
        for (byte[] key : source.keySet()) {
            String resultKey = Bytes.toString(key);
            String resultValue = Bytes.toString(source.get(key));
            result.put(resultKey, resultValue);
        }
        return result;
    }

    /**
     * Callback used to run the bean.
     *
     * @param args incoming application arguments
     * @throws Exception on error
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        importSolr();
    }
}